// Represents an error returned from the Linux kernel.
export type errno = int!;

// Given an integer error number, wraps it in an error type.
export fn wrap_errno(err: int) errno = err: errno;

// Checks the return value from a Linux syscall and, if found to be in error,
// returns the appropriate error. Otherwise, returns the original value.
fn wrap_return(r: u64) (errno | u64) = {
	if (r > -4096u64) {
		return (-(r: i64)): int: errno;
	};
	return r;
};

// Obtains a human-friendly reading of an [errno] (e.g. "Operation not
// permitted").
export fn strerror(err: errno) str = {
	return switch (err: int) {
		EPERM => "Operation not permitted",
		ENOENT => "No such file or directory",
		ESRCH => "No such process",
		EINTR => "Interrupted system call",
		EIO => "Input/output error",
		ENXIO => "No such device or address",
		E2BIG => "Argument list too long",
		ENOEXEC => "Exec format error",
		EBADF => "Bad file descriptor",
		ECHILD => "No child processes",
		EAGAIN => "Resource temporarily unavailable",
		ENOMEM => "Cannot allocate memory",
		EACCES => "Permission denied",
		EFAULT => "Bad address",
		ENOTBLK => "Block device required",
		EBUSY => "Device or resource busy",
		EEXIST => "File exists",
		EXDEV => "Invalid cross-device link",
		ENODEV => "No such device",
		ENOTDIR => "Not a directory",
		EISDIR => "Is a directory",
		EINVAL => "Invalid argument",
		ENFILE => "Too many open files in system",
		EMFILE => "Too many open files",
		ENOTTY => "Inappropriate ioctl for device",
		ETXTBSY => "Text file busy",
		EFBIG => "File too large",
		ENOSPC => "No space left on device",
		ESPIPE => "Illegal seek",
		EROFS => "Read-only file system",
		EMLINK => "Too many links",
		EPIPE => "Broken pipe",
		EDOM => "Numerical argument out of domain",
		ERANGE => "Numerical result out of range",
		EDEADLK => "Resource deadlock avoided",
		ENAMETOOLONG => "File name too long",
		ENOLCK => "No locks available",
		ENOSYS => "Function not implemented",
		ENOTEMPTY => "Directory not empty",
		ELOOP => "Too many levels of symbolic links",
		ENOMSG => "No message of desired type",
		EIDRM => "Identifier removed",
		ECHRNG => "Channel number out of range",
		EL2NSYNC => "Level 2 not synchronized",
		EL3HLT => "Level 3 halted",
		EL3RST => "Level 3 reset",
		ELNRNG => "Link number out of range",
		EUNATCH => "Protocol driver not attached",
		ENOCSI => "No CSI structure available",
		EL2HLT => "Level 2 halted",
		EBADE => "Invalid exchange",
		EBADR => "Invalid request descriptor",
		EXFULL => "Exchange full",
		ENOANO => "No anode",
		EBADRQC => "Invalid request code",
		EBADSLT => "Invalid slot",
		EBFONT => "Bad font file format",
		ENOSTR => "Device not a stream",
		ENODATA => "No data available",
		ETIME => "Timer expired",
		ENOSR => "Out of streams resources",
		ENONET => "Machine is not on the network",
		ENOPKG => "Package not installed",
		EREMOTE => "Object is remote",
		ENOLINK => "Link has been severed",
		EADV => "Advertise error",
		ESRMNT => "Srmount error",
		ECOMM => "Communication error on send",
		EPROTO => "Protocol error",
		EMULTIHOP => "Multihop attempted",
		EDOTDOT => "RFS specific error",
		EBADMSG => "Bad message",
		EOVERFLOW => "Value too large for defined data type",
		ENOTUNIQ => "Name not unique on network",
		EBADFD => "File descriptor in bad state",
		EREMCHG => "Remote address changed",
		ELIBACC => "Can not access a needed shared library",
		ELIBBAD => "Accessing a corrupted shared library",
		ELIBSCN => ".lib section in a.out corrupted",
		ELIBMAX => "Attempting to link in too many shared libraries",
		ELIBEXEC => "Cannot exec a shared library directly",
		EILSEQ => "Invalid or incomplete multibyte or wide character",
		ERESTART => "Interrupted system call should be restarted",
		ESTRPIPE => "Streams pipe error",
		EUSERS => "Too many users",
		ENOTSOCK => "Socket operation on non-socket",
		EDESTADDRREQ => "Destination address required",
		EMSGSIZE => "Message too long",
		EPROTOTYPE => "Protocol wrong type for socket",
		ENOPROTOOPT => "Protocol not available",
		EPROTONOSUPPORT => "Protocol not supported",
		ESOCKTNOSUPPORT => "Socket type not supported",
		EOPNOTSUPP => "Operation not supported",
		EPFNOSUPPORT => "Protocol family not supported",
		EAFNOSUPPORT => "Address family not supported by protocol",
		EADDRINUSE => "Address already in use",
		EADDRNOTAVAIL => "Cannot assign requested address",
		ENETDOWN => "Network is down",
		ENETUNREACH => "Network is unreachable",
		ENETRESET => "Network dropped connection on reset",
		ECONNABORTED => "Software caused connection abort",
		ECONNRESET => "Connection reset by peer",
		ENOBUFS => "No buffer space available",
		EISCONN => "Transport endpoint is already connected",
		ENOTCONN => "Transport endpoint is not connected",
		ESHUTDOWN => "Cannot send after transport endpoint shutdown",
		ETOOMANYREFS => "Too many references: cannot splice",
		ETIMEDOUT => "Connection timed out",
		ECONNREFUSED => "Connection refused",
		EHOSTDOWN => "Host is down",
		EHOSTUNREACH => "No route to host",
		EALREADY => "Operation already in progress",
		EINPROGRESS => "Operation now in progress",
		ESTALE => "Stale file handle",
		EUCLEAN => "Structure needs cleaning",
		ENOTNAM => "Not a XENIX named type file",
		ENAVAIL => "No XENIX semaphores available",
		EISNAM => "Is a named type file",
		EREMOTEIO => "Remote I/O error",
		EDQUOT => "Disk quota exceeded",
		ENOMEDIUM => "No medium found",
		EMEDIUMTYPE => "Wrong medium type",
		ECANCELED => "Operation canceled",
		ENOKEY => "Required key not available",
		EKEYEXPIRED => "Key has expired",
		EKEYREVOKED => "Key has been revoked",
		EKEYREJECTED => "Key was rejected by service",
		EOWNERDEAD => "Owner died",
		ENOTRECOVERABLE => "State not recoverable",
		ERFKILL => "Operation not possible due to RF-kill",
		EHWPOISON => "Memory page has hardware error",
		* => "Unknown Linux error code", // TODO: snprintf to add errno?
	};
};

// Gets the programmer-friendly name for an [errno] (e.g. EPERM).
export fn errname(err: errno) str = {
	return switch (err: int) {
		EPERM => "EPERM",
		ENOENT => "ENOENT",
		ESRCH => "ESRCH",
		EINTR => "EINTR",
		EIO => "EIO",
		ENXIO => "ENXIO",
		E2BIG => "E2BIG",
		ENOEXEC => "ENOEXEC",
		EBADF => "EBADF",
		ECHILD => "ECHILD",
		EAGAIN => "EAGAIN",
		ENOMEM => "ENOMEM",
		EACCES => "EACCES",
		EFAULT => "EFAULT",
		ENOTBLK => "ENOTBLK",
		EBUSY => "EBUSY",
		EEXIST => "EEXIST",
		EXDEV => "EXDEV",
		ENODEV => "ENODEV",
		ENOTDIR => "ENOTDIR",
		EISDIR => "EISDIR",
		EINVAL => "EINVAL",
		ENFILE => "ENFILE",
		EMFILE => "EMFILE",
		ENOTTY => "ENOTTY",
		ETXTBSY => "ETXTBSY",
		EFBIG => "EFBIG",
		ENOSPC => "ENOSPC",
		ESPIPE => "ESPIPE",
		EROFS => "EROFS",
		EMLINK => "EMLINK",
		EPIPE => "EPIPE",
		EDOM => "EDOM",
		ERANGE => "ERANGE",
		EDEADLK => "EDEADLK",
		ENAMETOOLONG => "ENAMETOOLONG",
		ENOLCK => "ENOLCK",
		ENOSYS => "ENOSYS",
		ENOTEMPTY => "ENOTEMPTY",
		ELOOP => "ELOOP",
		ENOMSG => "ENOMSG",
		EIDRM => "EIDRM",
		ECHRNG => "ECHRNG",
		EL2NSYNC => "EL2NSYNC",
		EL3HLT => "EL3HLT",
		EL3RST => "EL3RST",
		ELNRNG => "ELNRNG",
		EUNATCH => "EUNATCH",
		ENOCSI => "ENOCSI",
		EL2HLT => "EL2HLT",
		EBADE => "EBADE",
		EBADR => "EBADR",
		EXFULL => "EXFULL",
		ENOANO => "ENOANO",
		EBADRQC => "EBADRQC",
		EBADSLT => "EBADSLT",
		EBFONT => "EBFONT",
		ENOSTR => "ENOSTR",
		ENODATA => "ENODATA",
		ETIME => "ETIME",
		ENOSR => "ENOSR",
		ENONET => "ENONET",
		ENOPKG => "ENOPKG",
		EREMOTE => "EREMOTE",
		ENOLINK => "ENOLINK",
		EADV => "EADV",
		ESRMNT => "ESRMNT",
		ECOMM => "ECOMM",
		EPROTO => "EPROTO",
		EMULTIHOP => "EMULTIHOP",
		EDOTDOT => "EDOTDOT",
		EBADMSG => "EBADMSG",
		EOVERFLOW => "EOVERFLOW",
		ENOTUNIQ => "ENOTUNIQ",
		EBADFD => "EBADFD",
		EREMCHG => "EREMCHG",
		ELIBACC => "ELIBACC",
		ELIBBAD => "ELIBBAD",
		ELIBSCN => "ELIBSCN",
		ELIBMAX => "ELIBMAX",
		ELIBEXEC => "ELIBEXEC",
		EILSEQ => "EILSEQ",
		ERESTART => "ERESTART",
		ESTRPIPE => "ESTRPIPE",
		EUSERS => "EUSERS",
		ENOTSOCK => "ENOTSOCK",
		EDESTADDRREQ => "EDESTADDRREQ",
		EMSGSIZE => "EMSGSIZE",
		EPROTOTYPE => "EPROTOTYPE",
		ENOPROTOOPT => "ENOPROTOOPT",
		EPROTONOSUPPORT => "EPROTONOSUPPORT",
		ESOCKTNOSUPPORT => "ESOCKTNOSUPPORT",
		EOPNOTSUPP => "EOPNOTSUPP",
		EPFNOSUPPORT => "EPFNOSUPPORT",
		EAFNOSUPPORT => "EAFNOSUPPORT",
		EADDRINUSE => "EADDRINUSE",
		EADDRNOTAVAIL => "EADDRNOTAVAIL",
		ENETDOWN => "ENETDOWN",
		ENETUNREACH => "ENETUNREACH",
		ENETRESET => "ENETRESET",
		ECONNABORTED => "ECONNABORTED",
		ECONNRESET => "ECONNRESET",
		ENOBUFS => "ENOBUFS",
		EISCONN => "EISCONN",
		ENOTCONN => "ENOTCONN",
		ESHUTDOWN => "ESHUTDOWN",
		ETOOMANYREFS => "ETOOMANYREFS",
		ETIMEDOUT => "ETIMEDOUT",
		ECONNREFUSED => "ECONNREFUSED",
		EHOSTDOWN => "EHOSTDOWN",
		EHOSTUNREACH => "EHOSTUNREACH",
		EALREADY => "EALREADY",
		EINPROGRESS => "EINPROGRESS",
		ESTALE => "ESTALE",
		EUCLEAN => "EUCLEAN",
		ENOTNAM => "ENOTNAM",
		ENAVAIL => "ENAVAIL",
		EISNAM => "EISNAM",
		EREMOTEIO => "EREMOTEIO",
		EDQUOT => "EDQUOT",
		ENOMEDIUM => "ENOMEDIUM",
		EMEDIUMTYPE => "EMEDIUMTYPE",
		ECANCELED => "ECANCELED",
		ENOKEY => "ENOKEY",
		EKEYEXPIRED => "EKEYEXPIRED",
		EKEYREVOKED => "EKEYREVOKED",
		EKEYREJECTED => "EKEYREJECTED",
		EOWNERDEAD => "EOWNERDEAD",
		ENOTRECOVERABLE => "ENOTRECOVERABLE",
		ERFKILL => "ERFKILL",
		EHWPOISON => "EHWPOISON",
		* => "[unknown errno]", // TODO: snprintf to add errno?
	};
};

export def EPERM: int		= 1;
export def ENOENT: int		= 2;
export def ESRCH: int		= 3;
export def EINTR: int		= 4;
export def EIO: int		= 5;
export def ENXIO: int		= 6;
export def E2BIG: int		= 7;
export def ENOEXEC: int		= 8;
export def EBADF: int		= 9;
export def ECHILD: int		= 10;
export def EAGAIN: int		= 11;
export def ENOMEM: int		= 12;
export def EACCES: int		= 13;
export def EFAULT: int		= 14;
export def ENOTBLK: int		= 15;
export def EBUSY: int		= 16;
export def EEXIST: int		= 17;
export def EXDEV: int		= 18;
export def ENODEV: int		= 19;
export def ENOTDIR: int		= 20;
export def EISDIR: int		= 21;
export def EINVAL: int		= 22;
export def ENFILE: int		= 23;
export def EMFILE: int		= 24;
export def ENOTTY: int		= 25;
export def ETXTBSY: int		= 26;
export def EFBIG: int		= 27;
export def ENOSPC: int		= 28;
export def ESPIPE: int		= 29;
export def EROFS: int		= 30;
export def EMLINK: int		= 31;
export def EPIPE: int		= 32;
export def EDOM: int		= 33;
export def ERANGE: int		= 34;
export def EDEADLK: int		= 35;
export def ENAMETOOLONG: int	= 36;
export def ENOLCK: int		= 37;
export def ENOSYS: int		= 38;
export def ENOTEMPTY: int	= 39;
export def ELOOP: int		= 40;
export def ENOMSG: int		= 42;
export def EIDRM: int		= 43;
export def ECHRNG: int		= 44;
export def EL2NSYNC: int	= 45;
export def EL3HLT: int		= 46;
export def EL3RST: int		= 47;
export def ELNRNG: int		= 48;
export def EUNATCH: int		= 49;
export def ENOCSI: int		= 50;
export def EL2HLT: int		= 51;
export def EBADE: int		= 52;
export def EBADR: int		= 53;
export def EXFULL: int		= 54;
export def ENOANO: int		= 55;
export def EBADRQC: int		= 56;
export def EBADSLT: int		= 57;
export def EBFONT: int		= 59;
export def ENOSTR: int		= 60;
export def ENODATA: int		= 61;
export def ETIME: int		= 62;
export def ENOSR: int		= 63;
export def ENONET: int		= 64;
export def ENOPKG: int		= 65;
export def EREMOTE: int		= 66;
export def ENOLINK: int		= 67;
export def EADV: int		= 68;
export def ESRMNT: int		= 69;
export def ECOMM: int		= 70;
export def EPROTO: int		= 71;
export def EMULTIHOP: int	= 72;
export def EDOTDOT: int		= 73;
export def EBADMSG: int		= 74;
export def EOVERFLOW: int	= 75;
export def ENOTUNIQ: int	= 76;
export def EBADFD: int		= 77;
export def EREMCHG: int		= 78;
export def ELIBACC: int		= 79;
export def ELIBBAD: int		= 80;
export def ELIBSCN: int		= 81;
export def ELIBMAX: int		= 82;
export def ELIBEXEC: int	= 83;
export def EILSEQ: int		= 84;
export def ERESTART: int	= 85;
export def ESTRPIPE: int	= 86;
export def EUSERS: int		= 87;
export def ENOTSOCK: int	= 88;
export def EDESTADDRREQ: int	= 89;
export def EMSGSIZE: int	= 90;
export def EPROTOTYPE: int	= 91;
export def ENOPROTOOPT: int	= 92;
export def EPROTONOSUPPORT: int	= 93;
export def ESOCKTNOSUPPORT: int	= 94;
export def EOPNOTSUPP: int	= 95;
export def EPFNOSUPPORT: int	= 96;
export def EAFNOSUPPORT: int	= 97;
export def EADDRINUSE: int	= 98;
export def EADDRNOTAVAIL: int	= 99;
export def ENETDOWN: int	= 100;
export def ENETUNREACH: int	= 101;
export def ENETRESET: int	= 102;
export def ECONNABORTED: int	= 103;
export def ECONNRESET: int	= 104;
export def ENOBUFS: int		= 105;
export def EISCONN: int		= 106;
export def ENOTCONN: int	= 107;
export def ESHUTDOWN: int	= 108;
export def ETOOMANYREFS: int	= 109;
export def ETIMEDOUT: int	= 110;
export def ECONNREFUSED: int	= 111;
export def EHOSTDOWN: int	= 112;
export def EHOSTUNREACH: int	= 113;
export def EALREADY: int	= 114;
export def EINPROGRESS: int	= 115;
export def ESTALE: int		= 116;
export def EUCLEAN: int		= 117;
export def ENOTNAM: int		= 118;
export def ENAVAIL: int		= 119;
export def EISNAM: int		= 120;
export def EREMOTEIO: int	= 121;
export def EDQUOT: int		= 122;
export def ENOMEDIUM: int	= 123;
export def EMEDIUMTYPE: int	= 124;
export def ECANCELED: int	= 125;
export def ENOKEY: int		= 126;
export def EKEYEXPIRED: int	= 127;
export def EKEYREVOKED: int	= 128;
export def EKEYREJECTED: int	= 129;
export def EOWNERDEAD: int	= 130;
export def ENOTRECOVERABLE: int	= 131;
export def ERFKILL: int		= 132;
export def EHWPOISON: int	= 133;
